package com.tanhua.management.service;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.tanhua.management.mapper.ManagerMapper;
import com.tanhua.management.pojo.Manager;
import com.tanhua.management.vo.ErrorResult;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;


import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class SystemService {
    @Value("${jwt.secret}")
    private String secret;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private ManagerMapper managerMapper;
    @Autowired//自动装配
            JavaMailSenderImpl mailSender;//实施邮件发送的对象

    @Value("${spring.mail.username}")
    private String email;

    public ErrorResult login(String address, String username, String password, String uuid, String code) {

        //判断redis中该ip是否合法
        if (redisTemplate.opsForValue().get(address) != null) {
            if (Integer.valueOf(redisTemplate.opsForValue().get(address)) >= 3) {
                String msg = "你今日的验证次数已到上限,请24小时后再试";
                redisTemplate.opsForValue().set(address, redisTemplate.opsForValue().get(address), 1L, TimeUnit.DAYS);
                return ErrorResult.builder().errCode("000004").errMessage(msg).build();

            }
        }


        //创建条件查询器
        QueryWrapper<Manager> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username).eq("password", password);
        //获得查询结果
        Manager manager = this.managerMapper.selectOne(wrapper);
        if (manager == null) {
            String msg = "用户名或密码错误";
            //查询redis中ip的记录 没有记录添加
            if (!redisTemplate.hasKey(address)) {
                redisTemplate.opsForValue().set(address, "1", 1L, TimeUnit.DAYS);
            } else {
                //有该ip记录,将次数加1 次数到3将会拒绝访问
                Integer count = Integer.valueOf(redisTemplate.opsForValue().get(address)) + 1;

                if (count >= 3) {

                    log.info(address + "验证次数已到今日上限");
                }
                redisTemplate.opsForValue().set(address, count.toString(), 1L, TimeUnit.DAYS);

            }


            return ErrorResult.builder().errCode("000001").errMessage(msg).build();
        }
        //用户账密通过删除Redis中的缓存
        redisTemplate.delete(address);
        //检查验证码是否正确
        //   if (!StringUtils.equals(uuid, code)) {
        if (!redisTemplate.hasKey(uuid)) {
            String msg = "验证码已过期";
            return ErrorResult.builder().errCode("000002").errMessage(msg).build();
        }
        if (!StringUtils.equals(redisTemplate.opsForValue().get(uuid), code)) {
            String msg = "验证码输入有误";
            return ErrorResult.builder().errCode("000003").errMessage(msg).build();

        }
        // }
        //如果不是常用地址登录 给邮箱发送短信
        if (!StringUtils.equals(address, manager.getAddress())) {

            try {
                MimeMessage mimeMessage = mailSender.createMimeMessage();
                MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
                //MimeMessageHelper  可以设置发送附件
                mimeMessageHelper.setSubject("探花账号异常登录提醒(请勿回复此邮件)");
                mimeMessageHelper.setText("<!DOCTYPE html>\n" +
                        "<html>\n" +
                        "\n" +
                        "<head>\n" +
                        "    <meta charset=\"utf-8\">\n" +
                        "\n" +
                        "    <title>探花安全中心</title>\n" +
                        "\n" +
                        "\n" +
                        "    <div>\n" +
                        "        <h3>亲爱的探花用户：</h3>\n" +
                        "\n" +
                        "        <p> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;经系统检测，您的帐号" + username + "在其他设备成功登录：</p>\n" +
                        "        <p> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;时间：" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("MM/dd hh:mm:ss")) + "</p>\n" +
                        "        <p> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;登录业务：探花后台管理 设备ip：" + address + " </p>\n" +
                        "        <p> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;参考地点：安徽 合肥</p>\n" +
                        "        <p> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如非本人登录，请尽快前往探花安全中心修改密码。</p>\n" +
                        "        <p> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果是您本人操作，请忽略本次提醒。</p>\n" +
                        "\n" +
                        "         \n" +
                        "          \n" +
                        "    </div>\n" +
                        "    <style type=\"text/css\">\n" +
                        "        body {\n" +
                        "            background-color: red;\n" +
                        "        }\n" +
                        "    </style>\n" +
                        "</head>\n" +
                        "\n" +
                        "<body>\n" +
                        "</body>\n" +
                        "</html>\n", true);//这里设置true可以读取html语言，为文本设置样式，也可不填

                //这条语句可以发送图片
                //mimeMessageHelper.addAttachment("1.jpg", new File("C:\\Users\\lenovo\\Desktop\\团子.jpg"));//前面是设置文件的名称，后面是文件的绝对路径，也可以是相对路径
                mimeMessageHelper.setTo(manager.getEmail());
                mimeMessageHelper.setFrom(email);

                mailSender.send(mimeMessage);
            } catch (MessagingException e) {
                e.printStackTrace();
            }

        }
        //验证通过后将token状态变为有效
        redisTemplate.opsForValue().set("TOKEN_" + username.toUpperCase(), address);
        return null;
    }


    /**
     * 获取token的方法
     *
     * @param username
     * @return
     */
    public String gainToken(String username) {
        //生成token
        Map<String, Object> claims = new HashMap<>();
        //id主键自增,所有这里可以获取新用户的id,然后将用户的id放入token中
        claims.put("username", username);

        // 生成token
        String token = Jwts.builder()
                .setClaims(claims) //payload，存放数据的位置，不能放置敏感数据，如：密码等
                .signWith(SignatureAlgorithm.HS256, secret) //设置加密方法和加密盐
                .setExpiration(new DateTime().plusHours(12).toDate()) //设置过期时间，12小时后过期
                .compact();


        return token;

    }

    /**
     * 查询token是否合法
     *
     * @param token
     * @param address
     * @return
     */
    public Manager queryMangerByToken(String token, String address) {
        //非空判断
        String[] split = token.split(" ");
        if (split.length != 2) {
            return null;
        }

        try {
            // 通过token解析数据
            Map<String, Object> body = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(split[1])
                    .getBody();
            //根据解析出来数据,获取管理员用户名
            Manager manager = new Manager();
            manager.setUsername(body.get("username").toString());

            //判断redis中token是否为有效
            if (!StringUtils.equals(redisTemplate.opsForValue().get("TOKEN_" + manager.getUsername().toUpperCase()), address)) {
                //没有token的状态则已经登出,必须通过登录成功才可以改变token状态
                return null;
            }


            //需要返回Manager对象中的username,需要查询数据库获取username数据
            //若果每次都去查询数据库,必然会导致性能问题需要对管理员的用户名进行缓存操作
            //数据缓存时，需要设置过期时间，过期时间要与token的时间一致


            //定义一个字符串,作为存入Redis的key
            String redisKey = "TANHUA_Manager_UERNAME_" + manager.getUsername();
            String redisUid = "TANHUA_Manager_UID_" + manager.getUsername();
            //判断redis中是否有这条数据
            if (redisTemplate.hasKey(redisKey)) {
                //如果缓存中存在,获取这个数据
                // String username = redisTemplate.opsForValue().get(redisKey);
                String uid = redisTemplate.opsForValue().get(redisUid);
                //将uid设置进manager
                manager.setUid(uid);
            } else {
                //如果缓存中不存在,就去查询数据库
                QueryWrapper<Manager> wrapper = new QueryWrapper<>();
                wrapper.eq("username", manager.getUsername());
                Manager m = managerMapper.selectOne(wrapper);
                //将手机号码设置进user
                manager.setUid(m.getUid());

                //将手机号写入redis中
                //在jwt中的过期时间的单位为：秒
                long timeout = Long.valueOf(body.get("exp").toString()) * 1000 - System.currentTimeMillis();
                redisTemplate.opsForValue().set(redisKey, m.getUsername(), timeout, TimeUnit.MILLISECONDS);
                redisTemplate.opsForValue().set(redisUid, m.getUid(), timeout, TimeUnit.MILLISECONDS);
            }

            return manager;

        } catch (ExpiredJwtException e) {
            log.info("token已经过期！ token = " + token);
        } catch (Exception e) {
            log.error("token不合法！ token = " + token, e);
        }
        return null;
    }

    public Manager queryManager(String uid) {
        //通过id查询manager对象实例
        return this.managerMapper.selectById(uid);
    }

    public void saveVerification(String uuid, String code) {
        //设置验证码有效时间30s
        redisTemplate.opsForValue().set(uuid, code, 30L, TimeUnit.SECONDS);
    }

    public void logout(String token) {

        String[] split = token.split(" ");


        // 通过token解析数据
        Map<String, Object> body = Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(split[1])
                .getBody();
        //根据解析出来数据,获取管理员用户名

        redisTemplate.delete("TOKEN_" + body.get("username").toString().toUpperCase());


    }

}
